﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Web;
using System.IO;
using System.Diagnostics;

using RAFOJ.Structs;

namespace RAFOJ.Submitters
{
    class TimusSubmitter : Submitter
    {
        // Constants
        const string submitURL = "http://acm.timus.ru/submit.aspx";
        const string statusURL = "http://acm.timus.ru/status.aspx?author=";
        string[] possibleResults = { "Compiling", "Running", "Accepted", "Compilation error", "Crash", "Wrong answer", "Time limit exceeded", "Crash (access violation)", "Crash (stack overflow)", "Crash (integer division by zero)", "Output limit exceeded" };

        // Constructor
        public TimusSubmitter()
            : base("Timus")
        {

        }

        // Methods

        public void submit(Submission submission)
        {
            int idx = getIdleClient();
            submissions[idx] = submission;

            Thread thread = new Thread(() => work(idx));
            thread.Start();
        }

        private void work(int idx)
        {
            createHttpRequest(idx, createTimusPostData(idx), submitURL, true);
            getResult(idx);
            updateStandings(idx);
            waitForUnfreeze(idx, 10000);
        }

        public void getResult(int idx)
        {
            Console.WriteLine("Getting result for " + usernames[idx] + "...");

            Stopwatch sw = new Stopwatch();
            sw.Start();

            long cur = sw.ElapsedMilliseconds;
            int sleepInterval = 2000;

            while (sw.ElapsedMilliseconds - cur < 100000)
            {
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(statusURL + usernames[idx].Substring(0, usernames[idx].Length - 2));

                using (HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse())
                {
                    Stream dataStream = response.GetResponseStream();

                    // Open the stream using a StreamReader for easy access.
                    StreamReader reader = new StreamReader(dataStream);

                    // Read the content.
                    string responseFromServer = reader.ReadToEnd();

                    // Close http request
                    httpRequest.Abort();

                    // Get submission_id
                    int submission_id = parseSubmissionId(responseFromServer);

                    // Get submission status
                    submissions[idx].setStatus(parseSubmissionStatus(responseFromServer));

                    // Get error info of the submission
                    submissions[idx].setErrorInfo(getErrorInfo(idx, submission_id));

                    if (!submissions[idx].getStatus().Contains("ing")) return;
                }

                TimeSpan timeSpan = new TimeSpan(0, 0, 0, 0, sleepInterval);
                Thread.Sleep(timeSpan);

                sleepInterval += 500;
            }
            sw.Stop();
        }

        /**
         * Returns content of the page: "http://acm.timus.ru/ce.aspx?id=" + submission_id, if the submission status is "Compilation error".
         * Otherwise, return empty string.
         **/
        private string getErrorInfo(int idx, int submission_id)
        {
            if (submissions[idx].getStatus() != "Compilation error") return "";

            // get content of the: "http://acm.timus.ru/ce.aspx?id=" + submission_id
            httpRequests[idx] = (HttpWebRequest)WebRequest.Create("http://acm.timus.ru/ce.aspx?id=" + submission_id);
            httpRequests[idx].Method = "GET";
            httpRequests[idx].CookieContainer = cookies[idx];

            using (HttpWebResponse response = (HttpWebResponse)httpRequests[idx].GetResponse())
            {
                Stream dataStream = response.GetResponseStream();

                // Open the stream using a StreamReader for easy access.
                StreamReader reader = new StreamReader(dataStream);

                // Read the content.
                return reader.ReadToEnd();
            }
        }

        /**
         * Returns id of the current submission
         **/
        private int parseSubmissionId(string responseFromServer)
        {
            int p = responseFromServer.IndexOf("getsubmit.aspx/") + "getsubmit.aspx/".Length;
            int cid = 0;
            while (Char.IsDigit(responseFromServer[p]))
            {
                cid = 10 * cid + (int)responseFromServer[p] - (int)'0';
                p++;
            }
            return cid;
        }

        /**
         * Returns result of the current submission
         */
        private string parseSubmissionStatus(string responseFromServer)
        {
            int p = responseFromServer.IndexOf("class=\"verdict_") + "class=\"verdict_".Length;

            string tmp = responseFromServer.Substring(p, 250);
            string result = "Unknown error";
            int found = Int32.MaxValue;

            for (int k = 0; k < possibleResults.Length; k++)
            {
                p = tmp.IndexOf(possibleResults[k]);
                if (p != -1 && p <= found)
                {
                    found = p;
                    result = possibleResults[k];
                }
            }
            return result;
        }

        /**
         * Returns langueage id of the submission langueage
         **/
        private int getLanguageId(string language)
        {
            if (language == "C++") return 10;
            return 10;
        }

        private string createTimusPostData(int idx)
        {
            // Create post data that has to be sent
            string language = HttpUtility.UrlEncode(getLanguageId(submissions[idx].getLanguage()).ToString());
            string source = HttpUtility.UrlEncode(submissions[idx].getSource());
            string problemId = HttpUtility.UrlEncode(submissions[idx].getRealProblemId());

            string[] data = { "spaceID=1", "Action=submit", "JudgeID=" + usernames[idx], "Language=" + language, 
                                "Source=" + source, "ProblemNum=" + problemId };
            return createPostData(data);
        }
    }
}
